//websocket 注册包为1234+账户下属设备ID组成的字符串，不同设备间用|分割
//websocket 查询包为9901+18位设备ID+查询指令
//设备注册包为长度为22位的字符串，前4位1234，后18位为设备ID


const net = require('net');
const WebSocket = require('ws');
const ToModbusCRC16 = require('../../tools/crc16')
const { DeviceDataModel } = require('../../models/models')

function modbusTcpServer(){
// 引用Server类:
const WebSocketServer = WebSocket.Server;

// 实例化 创建wss服务器
const wss = new WebSocketServer({
    port: 3002
})

let wsDeviceIdPool = {}
let wsDeviceIpPool = {}
//设备连接索引池 通过设备号找到连接
let deviceIdPool = {}
//连接ip端口设备索引池 通过连接找到设备号
let deviceIpPool = {}

wss.on('connection', (ws, req) => {
    const clientIp = req.connection.remoteAddress
    const clientPort = req.connection.remotePort
    ws.on('message', (mes) => {
        //是否为注册包
        if (mes.substr(0, 4) === '1234') {
            //长度为18位为设备id
            const wsDevice = mes.substr(4).split('|')
            //地址端口号ip池对应设备数组
            wsDeviceIpPool[clientIp + clientPort] = wsDevice;
            wsDevice.forEach(item => {
                //设备池对应连接
                wsDeviceIdPool[item] = ws;
                
            });
        }
        //是否为查询指令
        else if (mes.substr(0, 4) === '9901') {
            const deviceId = mes.substr(4, 18);
            //查询指令
            const modBusQuery = Buffer.from(mes.substr(22), 'hex');
            deviceIdPool[deviceId].write(modBusQuery)
        }

    })

    //关闭连接时从索引池删除
    ws.on('close', () => {
        if (wsDeviceIpPool[clientIp + clientPort]) {
            wsDeviceIpPool[clientIp + clientPort].forEach(item => {
                delete wsDeviceIdPool[item]
            })
            delete wsDeviceIpPool[clientIp + clientPort]
        }
    })

    ws.on('error', () => {
        if (wsDeviceIpPool[clientIp + clientPort]) {
            wsDeviceIpPool[clientIp + clientPort].forEach(item => {
                delete wsDeviceIdPool[item]
            })
            delete wsDeviceIpPool[clientIp + clientPort]
        }
    })
})




//创建tcp服务器
const tcpServer = net.createServer().listen(15000)

tcpServer.on('connection', (socket) => {
    socket.on('data', (data) => {
        //转为16十进制数据
        const hexData = data.toString('hex');
        const norData = data.toString()
        //判断是否是设备注册包
        if (hexData.substr(0, 4) === '1234' && hexData.length == 22) {
            const deviceId = hexData.substr(4)
            //设备上线存入连接
            deviceIdPool[deviceId] = socket;
            deviceIpPool[socket.remoteAddress + socket.remotePort] = deviceId;
            //推送设备上线通知
            if (wsDeviceIdPool[deviceId]) {
                wsDeviceIdPool[deviceId].write('sx' + deviceId)
            }
        }
        //如果9901开头为查询指令
        else if (norData.substr(0, 4) === '9901' && norData.length > 25) {
            const deviceId = norData.substr(4, 18)
            const modBusQuery = norData.substr(22)
            //向指定设备发送查询指令
            if (deviceIdPool[deviceId]) {
                deviceIdPool[deviceId].write(Buffer.from(modBusQuery, 'hex'))
                //保存此次发送的指令和设备ID
                deviceIdPool[deviceId].lastQuery = Buffer.from(modBusQuery, 'hex')
            }


        }


        else if (deviceIpPool[socket.remoteAddress + socket.remotePort] ) {
            //获取设备ID
            const deviceId = deviceIpPool[socket.remoteAddress + socket.remotePort]
            //进行crc校验
            if (ToModbusCRC16(hexData.slice(0,-4)) == hexData.substr(-4)) {
                //如果存在web客户端向客户端推送实时数据
                if (wsDeviceIdPool[deviceId]) {
                    wsDeviceIdPool[deviceId].send(deviceId  + hexData)
                }
                //存入数据库
                new DeviceDataModel({
                    deviceId: deviceIpPool[socket.remoteAddress + socket.remotePort],
                    slaverIndex: hexData.substr(0, 2),
                    value: hexData ,  //  hexData.slice(6, -4),
                    createTime: Date.now()
                }).save()
            } else {
                //crc校验失败重发指令
                deviceIdPool[deviceId].write(deviceIdPool[deviceId].lastQuery)
                console.log(`重新发送${deviceIdPool[deviceId].lastQuery}`)

            }
        } else {
            //收到未注册的信息
            console.log(hexData)
        }
    })
    //当连接关闭时删除索引池
    socket.on('close', () => {
        delete deviceIdPool[deviceIpPool[socket.remoteAddress + socket.remotePort]]
        delete deviceIpPool[socket.remoteAddress + socket.remotePort]
    })

    socket.on('error', () => {
        delete deviceIdPool[deviceIpPool[socket.remoteAddress + socket.remotePort]]
        delete deviceIpPool[socket.remoteAddress + socket.remotePort]
    })
})

}


module.exports = modbusTcpServer